﻿using Core.Framework;
using Core.Framework.Common;
using Dashboard.Models;
using Environment.Interfaces;
using Microsoft.AspNetCore.Http;
using System;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Dashboard.Middlewares
{
    public class CheckStartupMiddlewares
    {
        static bool isConfiged = false;
        IToolCenter toolCenter;
        private readonly RequestDelegate _next;
        const string gatewaydatabasePath = "../gatewaydatabase.config";
        const string startingURL = "/starting";
        readonly string[] stopChats = new string[] { "_blazor", "/_blazor", "/nodestatus" };

        public CheckStartupMiddlewares(IToolCenter toolCenter, RequestDelegate next)
        {
            this._next = next ?? throw new ArgumentNullException(nameof(next));
            this.toolCenter = toolCenter;
        }

        public async Task Invoke(HttpContext context)
        {
            //bool isPostRequest = context.Request.Method == "POST";
            bool isWebSocket = context.WebSockets.IsWebSocketRequest;
            bool isStop = stopChats.Where(chat => context.Request.Path.Value.StartsWith(chat)).Any();

            //if (isPostRequest || isWebSocket || isStop)
            if (isWebSocket || isStop)
            {
                //var readerPOST = new StreamReader(context.Request.Body);
                //var bodyPOST = readerPOST.ReadToEndAsync().Result;
                await this._next(context);
                return;
            }

            var isStaringRouter = context.Request.Path.Value.ToLower().Equals(startingURL);

            if (!isConfiged)
            {
                if (await this.CheckDataBaseInstance())
                {
                    isConfiged = true;
                    context.Response.Redirect("/User/Login");
                }
                else if (!isStaringRouter)
                {
                    context.Response.Redirect("/starting");
                    return;
                }
            }
            else if (isStaringRouter)
            {
                context.Response.Redirect("/User/Login");
                return;
            }

            await this._next(context);
        }

        private async Task<bool> CheckDataBaseInstance()
        {
            //检查数据库环境
            if (File.Exists(gatewaydatabasePath))
            {
                // 拿到用户名密码尝试连接
                // 成功就是 True
                // 否则检查docker容器是否未创建
                var value = File.ReadAllText(gatewaydatabasePath);
                var dbParameter = Newtonsoft.Json.JsonConvert.DeserializeObject<CreateDataBaseRequest>(value);
                if (this.CheckConnection(dbParameter.Passward, dbParameter.Port, 5))
                {
                    AppSetting.SetiToolGatewayOptions(dbParameter.SqlConnection, dbParameter.Seed);

                    // Test
                    // AppSetting.SetiToolGatewayOptions("Data Source=1.117.167.53,2533;database=iTool.Gateway;uid=sa;pwd=zhuJIAN30.3..;MultipleActiveResultSets=true;", dbParameter.Seed);

                    var config = await this.toolCenter.GetiToolConfigure();
                    if (config != null)
                    {
                        AppSetting.SetiToolLoggerOptions(config.LoggerDatabases.First());
                    }
                    return true;
                }
                else
                {
                    // 启动
                    Shell.Excuter($"docker start iToolGatewaySqlServer");
                    Thread.Sleep(2000);
                    if (this.CheckConnection(dbParameter.Passward, dbParameter.Port, 5))
                    {
                        AppSetting.SetiToolGatewayOptions(dbParameter.SqlConnection, dbParameter.Seed);
                        var config = await this.toolCenter.GetiToolConfigure();
                        if (config != null)
                        {
                            AppSetting.SetiToolLoggerOptions(config.LoggerDatabases.First());
                        }
                        return true;
                    }
                    else
                    {

                        // 创建 --restart always
                        string shellResult = Shell.Excuter($"docker run --restart=always -e ACCEPT_EULA=Y -e MSSQL_PID=\"Developer\" -e MSSQL_SA_PASSWORD=\"{dbParameter.Passward}\" -e MSSQL_TCP_PORT={dbParameter.Port} -p {dbParameter.Port}:{dbParameter.Port} --name iToolGatewaySqlServer -d microsoft/mssql-server-linux");

                        //var resultArr = shellResult.Replace("\n", "").Replace("\r", "").Split("&exit");

                        Thread.Sleep(1000);
                        if (this.CheckConnection(dbParameter.Passward, dbParameter.Port))
                        {
                            AppSetting.SetiToolGatewayOptions(dbParameter.SqlConnection, dbParameter.Seed);
                            var config = await this.toolCenter.GetiToolConfigure();
                            if (config != null)
                            {
                                AppSetting.SetiToolLoggerOptions(config.LoggerDatabases.First());
                            }
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
            }

            return false;
        }

        private bool CheckConnection(string pwd, int port, int isRetryIndex = 0)
        {
            string conneciotnString = $"Data Source=127.0.0.1,{port};database=master;uid=sa;pwd={pwd};MultipleActiveResultSets=true;Connect Timeout=2";
            // Test
            // conneciotnString = $"Data Source=1.117.167.53,{port};database=master;uid=sa;pwd={pwd};MultipleActiveResultSets=true;Connect Timeout=2";
            
            try
            {
                using (var connection = new SqlConnection(conneciotnString))
                {
                    connection.Open();
                }
                return true;
            }
            catch (Exception)
            {
                if (isRetryIndex < 5)
                {
                    isRetryIndex++;
                    Thread.Sleep(isRetryIndex * 1000);
                    return CheckConnection(pwd, port, isRetryIndex);
                }

                return false;
            }
        }

    }
}
